package main

import (
	"encoding/json"
	"fmt"
	"os"
)

type Serverslice2 struct {
	Total int `json:"total"`
	Count int `json:"count"`
	Start int `json:"start"`
}

type Timestamps struct {
	Created  int64 `json:"created,omitempty" yaml:"created,omitempty"`
	Modified int64 `json:"modified,omitempty" yaml:"modified,omitempty"`
	Origin   int64 `json:"origin,omitempty" yaml:"origin,omitempty"`
}

type DescribedObject struct {
	Timestamps  `yaml:",inline"`
	Description string `json:"description" yaml:"description,omitempty"` // Description. Capicé?
}

type DeviceProfile struct {
	DescribedObject `yaml:",inline"`
	Id              string `json:"id" yaml:"id,omitempty"`
	Name            string `json:"name" yaml:"name,omitempty"`                 // Non-database identifier (must be unique)
	Manufacturer    string `json:"manufacturer" yaml:"manufacturer,omitempty"` // Manufacturer of the device
	Model           string `json:"model" yaml:"model,omitempty"`               // Model of the device
	Labels          []string          `json:"labels" yaml:"labels,flow,omitempty"`        // Labels used to search for groups of profiles
	DeviceResources []DeviceResource  `json:"deviceResources" yaml:"deviceResources,omitempty"`
	DeviceCommands  []ProfileResource `json:"deviceCommands" yaml:"deviceCommands,omitempty"`
	CoreCommands    []Command         `json:"coreCommands" yaml:"coreCommands,omitempty"`
}

type DeviceResource struct {
	Description string            `json:"description" yaml:"description,omitempty"`
	Name        string            `json:"name" yaml:"name,omitempty"`
	Tag         string            `json:"tag" yaml:"tag,omitempty"`
	Properties  ProfileProperty   `json:"properties" yaml:"properties"`
	Attributes  map[string]string `json:"attributes" yaml:"attributes,omitempty"`
}

type ProfileProperty struct {
	Value PropertyValue `json:"value"`
	Units Units         `json:"units"`
}

type PropertyValue struct {
	Type          string `json:"type" yaml:"type,omitempty"`                 // ValueDescriptor Type of property after transformations
	ReadWrite     string `json:"readWrite" yaml:"readWrite,omitempty"`       // Read/Write Permissions set for this property
	Minimum       string `json:"minimum" yaml:"minimum,omitempty"`           // Minimum value that can be get/set from this property
	Maximum       string `json:"maximum" yaml:"maximum,omitempty"`           // Maximum value that can be get/set from this property
	DefaultValue  string `json:"defaultValue" yaml:"defaultValue,omitempty"` // Default value set to this property if no argument is passed
	Size          string `json:"size" yaml:"size,omitempty"`                 // Size of this property in its type  (i.e. bytes for numeric types, characters for string types)
	Mask          string `json:"mask" yaml:"mask,omitempty"`                 // Mask to be applied prior to get/set of property
	Shift         string `json:"shift" yaml:"shift,omitempty"`               // Shift to be applied after masking, prior to get/set of property
	Scale         string `json:"scale" yaml:"scale,omitempty"`               // Multiplicative factor to be applied after shifting, prior to get/set of property
	Offset        string `json:"offset" yaml:"offset,omitempty"`             // Additive factor to be applied after multiplying, prior to get/set of property
	Base          string `json:"base" yaml:"base,omitempty"`                 // Base for property to be applied to, leave 0 for no power operation (i.e. base ^ property: 2 ^ 10)
	Assertion     string `json:"assertion" yaml:"assertion,omitempty"`       // Required value of the property, set for checking error state.  Failing an assertion condition will mark the device with an error state
	Precision     string `json:"precision" yaml:"precision,omitempty"`
	FloatEncoding string `json:"floatEncoding" yaml:"floatEncoding,omitempty"` // FloatEncoding indicates the representation of floating value of reading.  It should be 'Base64' or 'eNotation'
	MediaType     string `json:"mediaType,omitempty"`
}

type Units struct {
	Type         string `json:"type" yaml:"type,omitempty"`
	ReadWrite    string `json:"readWrite" yaml:"readWrite,omitempty"`
	DefaultValue string `json:"defaultValue" yaml:"defaultValue,omitempty"`
}

type ProfileResource struct {
	Name string              `json:"name" yaml:"name,omitempty"`
	Get  []ResourceOperation `json:"get" yaml:"get,omitempty"`
	Set  []ResourceOperation `json:"set" yaml:"set,omitempty"`
}

type ResourceOperation struct {
	Index     string            `json:"index" yaml:"index,omitempty"`
	Operation string            `json:"operation" yaml:"operation,omitempty"`
	Object    string            `json:"object" yaml:"object,omitempty"`
	Parameter string            `json:"parameter" yaml:"parameter,omitempty"`
	Resource  string            `json:"resource" yaml:"resource,omitempty"`
	Secondary []string          `json:"secondary" yaml:"secondary,omitempty"`
	Mappings  map[string]string `json:"mappings" yaml:"mappings,omitempty"`
}

type Command struct {
	Timestamps  `yaml:",inline"`
	Id          string `json:"id" yaml:"id,omitempty"`     // Id is a unique identifier, such as a UUID
	Name        string `json:"name" yaml:"name,omitempty"` // Command name (unique on the profile)
	Get         Get    `json:"get" yaml:"get,omitempty"`   // Get Command
	Put         Put    `json:"put" yaml:"put,omitempty"`   // Put Command
	isValidated bool   // internal member used for validation check
}

type Get struct {
	Action `yaml:",inline"`
}

type Put struct {
	Action         `yaml:",inline"`
	ParameterNames []string `json:"parameterNames" yaml:"parameterNames,omitempty"`
}

type Action struct {
	Path      string     `json:"path" yaml:"path,omitempty"`           // Path used by service for action on a device or sensor
	Responses []Response `json:"responses" yaml:"responses,omitempty"` // Responses from get or put requests to service
	URL       string     `json:"url,omitempty" yaml:"url,omitempty"`   // Url for requests from command service
}

type Response struct {
	Code           string   `json:"code" yaml:"code,omitempty"`
	Description    string   `json:"description" yaml:"description,omitempty"`
	ExpectedValues []string `json:"expectedValues" yaml:"expectedValues,omitempty"`
}

func main() {
	var s Serverslice2
	str := `{"count": 10,"start": 0,"total": 1626}`
	json.Unmarshal([]byte(str), &s)
	fmt.Fprintf(os.Stdout, "s = %v .\n",s)
	fmt.Println("s = ",s)


	var sd DeviceProfile
	str2 := `{"created": 1559790450892,"modified": 1559790450892,"origin": 1559790450832,"description": "GS1 AC Drive Motor Controller","id": "5cf883729008b0a96e6e0c1d","name": "GS1-VariableSpeedMotor","manufacturer": "Automation Direct","model": "GS1-10P5",
"labels": ["motor", "Industrial", "Motor Controller", "variable speed"],
"deviceResources": [{
		"description": "PWM Output Frequency for driving motor.",
		"name": "OutputFrequency",
		"properties": {
			"value": {
				"type": "Integer",
				"readWrite": "RW",
				"defaultValue": "1",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "1.0",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "Hz"
			}
		},
		"attributes": {
			"HoldingRegister": "8451"
		}
	}, {
		"description": "RPM speed of the motor.",
		"name": "RPM",
		"properties": {
			"value": {
				"type": "Float",
				"readWrite": "RW",
				"minimum": "0",
				"maximum": "1500",
				"defaultValue": "1",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "1.0",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "rpm"
			}
		},
		"attributes": {
			"HoldingRegister": "8455"
		}
	}, {
		"description": "Output Voltage driving the motor.",
		"name": "OutputVoltage",
		"properties": {
			"value": {
				"type": "Float",
				"readWrite": "RW",
				"defaultValue": "1",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "0.1",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "Volts"
			}
		},
		"attributes": {
			"HoldingRegister": "8454"
		}
	}, {
		"description": "On/Off Status of the motor.",
		"name": "Status",
		"properties": {
			"value": {
				"type": "Integer",
				"readWrite": "RW",
				"minimum": "0",
				"maximum": "1",
				"defaultValue": "0",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "1.0",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "Enabled/Disabled"
			}
		},
		"attributes": {
			"HoldingRegister": "2331"
		}
	}, {
		"description": "Clockwise/Counterclockwise Direction of the motor.",
		"name": "Direction",
		"properties": {
			"value": {
				"type": "Integer",
				"readWrite": "RW",
				"minimum": "0",
				"maximum": "1",
				"defaultValue": "0",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "1.0",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "Clockwise/CounterClockwise"
			}
		},
		"attributes": {
			"HoldingRegister": "2332"
		}
	}, {
		"description": "PWM Frequency driving the motor.",
		"name": "Frequency",
		"properties": {
			"value": {
				"type": "Integer",
				"readWrite": "RW",
				"defaultValue": "0",
				"size": "2",
				"mask": "0x00",
				"shift": "0",
				"scale": "2.875",
				"offset": "0.0",
				"base": "0"
			},
			"units": {
				"type": "String",
				"readWrite": "R",
				"defaultValue": "Hz"
			}
		},
		"attributes": {
			"HoldingRegister": "2330"
		}
	}],
"deviceCommands": [{
		"name": "OutputVoltage",
		"get": [{
			"operation": "get",
			"object": "OutputVoltage",
			"parameter": "OutputVoltage"
		}]
	}, {
		"name": "Status",
		"get": [{
			"operation": "get",
			"object": "Status",
			"parameter": "Status"
		}],
		"set": [{
			"index": "1",
			"operation": "set",
			"object": "Status",
			"parameter": "Status"
		}]
	}, {
		"name": "RPM",
		"get": [{
			"operation": "get",
			"object": "RPM",
			"parameter": "RPM"
		}],
		"set": [{
			"index": "1",
			"operation": "set",
			"object": "Status",
			"parameter": "1"
		}, {
			"index": "2",
			"operation": "set",
			"object": "Frequency",
			"parameter": "RPM"
		}]
	}, {
		"name": "AllValues",
		"get": [{
			"index": "1",
			"operation": "get",
			"object": "RPM",
			"parameter": "RPM"
		}, {
			"index": "2",
			"operation": "get",
			"object": "OutputVoltage",
			"parameter": "OutputVoltage"
		}]
	}, {
		"name": "MotorControl",
		"get": [{
			"operation": "get",
			"resource": "AllValues"
		}],
		"set": [{
			"operation": "set",
			"parameter": "RPM",
			"resource": "RPM"
		}]
	}],
"coreCommands": [{
		"get": {},
		"put": {}
	}]}`
	json.Unmarshal([]byte(str2), &sd)
	fmt.Println("sd = ",sd)
}